package com.dream.filter;

import cn.hutool.jwt.JWTUtil;
import com.dream.util.JwtTokenUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Objects;


/**
 * OncePerRequestFilter类，其中的doFilterInternal需要调用一次进行验证token
 * 我们需要重写doFilterInternal方法，自定义全局验证token规则
 */
@Slf4j
public class BasicAuthenticationTokenFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // get token from header:  Authorization: Bearer <token>
        String authHeader = request.getHeader(JwtTokenUtils.AUTH_HEADER);

        //如果没有token，放行
        if (Objects.isNull(authHeader) || !authHeader.startsWith(JwtTokenUtils.AUTH_HEADER_TYPE)){
            filterChain.doFilter(request,response);
            return;
        }
        String authToken = authHeader.split(" ")[1];
        log.info("authToken:{}" , authToken);
        //verify token
        if (!JWTUtil.verify(authToken, JwtTokenUtils.JWT_SIGN_KEY.getBytes(StandardCharsets.UTF_8))) {
            log.info("invalid token");
            filterChain.doFilter(request,response);
            return;
        }
        //解析token获取用户名称
        final String userName = (String) JWTUtil.parseToken(authToken).getPayload("username");
        //从redis中获取当前用户的token,并且和传来的authHeader做比较

        //比较不成功，直接返回，不放行filter

        //比较成功，生成Authentication对象，刷新redis中token的时间，并且

        // 注意，这里使用的是3个参数的构造方法，此构造方法将认证状态设置为true
        UsernamePasswordAuthenticationToken authentication =
                new UsernamePasswordAuthenticationToken("admin", "admin", new ArrayList<>());

        //将认证过了凭证保存到security的上下文中以便于在程序中使用
        SecurityContextHolder.getContext().setAuthentication(authentication);
        filterChain.doFilter(request, response);
    }

}
